package cn.green.mvc.dao;

import cn.green.config.exceptions.QTableConfigException;
import cn.green.core.adapt.models.table.OrmTable;
import cn.green.core.annos.table.QTable;
import cn.green.core.components.database.session.dql.QuerySession;
import cn.green.core.excel.exceptions.QExcelException;
import cn.green.core.model.QFieldModel;
import cn.green.core.model.QFieldOrder;
import cn.green.core.scanner.store.OrmTableStore;
import cn.green.manage.cache.QCache;
import cn.green.manage.service.QDmlService;
import cn.green.manage.service.QDqlService;
import cn.green.mapper.store.EntityTableMapperStore;
import cn.green.mvc.entity.OrmTableEntity;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.green.core.common.QTableConstant.DQL.PRIMARY_TABLE;

/**
 * @author wang.yishu
 * @version 1.0
 * @className OrmTableDao
 * @description 表 curd dao
 * @date 2025/5/22 14:58
 */
public abstract class OrmTableDao<T extends OrmTableEntity> {
    protected QDqlService qdqlService;
    protected QDmlService qdmlService;
    protected QCache cache;
    protected OrmTable table;
    protected Class<T> clazz;
    @Getter
    protected String tableName;
    @Getter
    protected String sourceName;
    @Getter
    protected String schemeName;
    @Getter
    protected String tableAlias;
    public OrmTableDao(QDqlService qdqlService,
                       QDmlService qdmlService,
                       QCache qCache,
                       Class<T> clazz) {
        this.qdqlService = qdqlService;
        this.qdmlService = qdmlService;
        this.cache = qCache;
        this.clazz = clazz;
        QTable annotation = clazz.getDeclaredAnnotation(QTable.class);
        if (annotation != null) {
            this.tableName = annotation.name();
            this.sourceName = annotation.source();
            this.schemeName = annotation.scheme();
            this.tableAlias = annotation.alias();
        } else {
            throw new QTableConfigException("QOrm annotation is NULL!");
        }
    }
    public JSONArray list(JSONObject param) {
        List<QFieldOrder> queryOrder = this.getQueryOrder();
        if (queryOrder != null && !queryOrder.isEmpty()) {
            QuerySession.QueryOrder.addOrders(this.sourceName, this.schemeName, this.tableName, queryOrder);
        }
        try {
            return this.qdqlService.list(sourceName, schemeName, tableName, param);
        } finally {
            QuerySession.QueryOrder.clearOrders(this.sourceName, this.schemeName, this.tableName);
        }

    }
    public JSONArray simpleList(JSONObject param) {
        List<QFieldOrder> queryOrder = this.getQueryOrder();
        if (queryOrder != null && !queryOrder.isEmpty()) {
            QuerySession.QueryOrder.addOrders(this.sourceName, this.schemeName, this.tableName, queryOrder);
        }
        try {
            return this.qdqlService.simpleList(sourceName, schemeName, tableName, param);
        } finally {
            QuerySession.QueryOrder.clearOrders(this.sourceName, this.schemeName, this.tableName);
        }

    }
    public List<T> list(T param) {
        JSONObject paramJson = EntityTableMapperStore.get(this.clazz).toJson(param);
        JSONArray list = this.list(paramJson);
        List<T> result = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            for (int i = 0; i < list.size(); i++) {
                T t = EntityTableMapperStore.get(this.clazz).toEntity(list.getJSONObject(i));
                result.add(t);
            }
        }
        return result;
    }
    public List<T> simpleList(T param) {
        JSONObject paramJson = EntityTableMapperStore.get(this.clazz).toJson(param);
        JSONArray list = this.simpleList(paramJson);
        List<T> result = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            for (int i = 0; i < list.size(); i++) {
                JSONObject row = list.getJSONObject(i);
                JSONObject nRow = new JSONObject();
                row.keySet().forEach(k -> {
                    if (k.startsWith(PRIMARY_TABLE)) {
                        nRow.put(k.substring(PRIMARY_TABLE.length() + 1), row.get(k));
                    }
                });
                T t = EntityTableMapperStore.get(this.clazz).toEntity(nRow);
                result.add(t);
            }
        }
        return result;
    }
    public JSONArray query(JSONObject param) {
        List<QFieldOrder> queryOrder = this.getQueryOrder();
        if (queryOrder != null && !queryOrder.isEmpty()) {
            QuerySession.QueryOrder.addOrders(this.sourceName, this.schemeName, this.tableName, queryOrder);
        }
        try {
            return this.qdqlService.select(sourceName, schemeName, tableName,  param);
        } finally {
            QuerySession.QueryOrder.clearOrders(this.sourceName, this.schemeName, this.tableName);
        }
    }
    public JSONObject page(JSONObject param) {
        List<QFieldOrder> queryOrder = this.getQueryOrder();
        if (queryOrder != null && !queryOrder.isEmpty()) {
            QuerySession.QueryOrder.addOrders(this.sourceName, this.schemeName, this.tableName, queryOrder);
        }
        try {
            return this.qdqlService.page(sourceName, schemeName, tableName,  param);
        } finally {
            QuerySession.QueryOrder.clearOrders(this.sourceName, this.schemeName, this.tableName);
        }
    }
    public Map<String, Object> page(T param) {
        JSONObject paramJson = EntityTableMapperStore.get(this.clazz).toJson(param);
        JSONObject page = this.page(paramJson);
        HashMap<String, Object> pageMap = new HashMap<>();
        pageMap.put("total", page.get("total"));
        JSONArray data = page.getJSONArray("data");
        List<T> dataList = new ArrayList<>();
        if (data != null && !data.isEmpty()) {
            for (int i = 0; i < data.size(); i++) {
                T t = EntityTableMapperStore.get(this.clazz).toEntity(data.getJSONObject(i));
                dataList.add(t);
            }
        }
        pageMap.put("data", dataList);
        return pageMap;
    }
    public JSONObject detail(JSONObject param) {
        if (table == null) {
            this.table = OrmTableStore.get(sourceName, schemeName, tableName);
        }
        QFieldModel primaryField = table.getPrimary();
        if (primaryField == null) {
            throw new QExcelException("There is no primary table");
        }
        Object pv = param.get(primaryField.getFieldName());
        return this.qdqlService.detail(sourceName, schemeName, tableName,  pv);
    }
    public T get(T param) {
        JSONObject paramJson = EntityTableMapperStore.get(this.clazz).toJson(param);
        JSONObject detail = this.detail(paramJson);
        return EntityTableMapperStore.get(this.clazz).toEntity(detail);
    }
    public JSONObject detail(Object primary) {
        return this.qdqlService.detail(sourceName, schemeName, tableName,  primary);
    }
    public T get(Object primary) {
        JSONObject detail = this.detail(primary);
        return EntityTableMapperStore.get(this.clazz).toEntity(detail);
    }
    public Object save(JSONObject entity) {
        if (table == null) {
            this.table = OrmTableStore.get(sourceName, schemeName, tableName);
        }
        QFieldModel primary = table.getPrimary();
        if (primary == null) {
            return this.qdmlService.istRecordAndSetCache(sourceName, schemeName, tableName,  entity);
        }
        Object primaryVal = entity.get(primary.getFieldName());
        if (primaryVal == null) {
            return this.qdmlService.istRecordAndSetCache(sourceName, schemeName, tableName,  entity);
        } else {
            String[] conditions = new String[1];
            conditions[0] = primary.getFieldName();
            return this.qdmlService.updRecordAndUpdCache(sourceName, schemeName, tableName,  entity, conditions);
        }
    }
    public Object save(T entity) {
        JSONObject entityJson = EntityTableMapperStore.get(this.clazz).toJson(entity);
        return this.save(entityJson);
    }
    public Object delete(JSONObject entity) {
        return this.qdmlService.delRecord(sourceName, schemeName, tableName,  entity);
    }
    public Object delete(Object primary) {
        if (table == null) {
            this.table = OrmTableStore.get(sourceName, schemeName, tableName);
        }
        QFieldModel primaryField = table.getPrimary();
        if (primaryField == null) {
            throw new QExcelException("There is no primary table");
        }
        JSONObject param = new JSONObject();
        param.put(primaryField.getFieldName(), primary);
        String[] conditions = new String[1];
        conditions[0] = primaryField.getFieldName();
        return this.qdmlService.delRecord(sourceName, schemeName, tableName,  param, conditions);
    }
    public Object remove(T entity) {
        JSONObject entityJson = EntityTableMapperStore.get(this.clazz).toJson(entity);
        return this.delete(entityJson);
    }
    public Object remove(Object primary) {
        return this.delete(primary);
    }
    public List<QFieldOrder> getQueryOrder() {
        return null;
    }
}
